package cn.dansj.common.utils.reflect;

import cn.dansj.common.utils.transfer.AssertUtils;

import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.Arrays;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

class ConstructorUtils {
    // 缓存条目：包含构造方法和访问级别信息
    private static class CacheEntry {
        final Constructor<?> constructor;
        final boolean isPublic;

        CacheEntry(Constructor<?> constructor) {
            this.constructor = constructor;
            this.isPublic = (constructor.getModifiers() & Modifier.PUBLIC) != 0;
        }
    }

    // 高效缓存键
    private static class CacheKey {
        private final Class<?> clazz;
        private final Class<?>[] paramTypes;
        private final int hashCode;

        public CacheKey(Class<?> clazz, Class<?>... paramTypes) {
            this.clazz = clazz;
            this.paramTypes = paramTypes != null ? paramTypes.clone() : new Class<?>[0];
            this.hashCode = calculateHashCode();
        }

        private int calculateHashCode() {
            int result = clazz.hashCode();
            for (Class<?> paramType : paramTypes) {
                result = 31 * result + paramType.hashCode();
            }
            return result;
        }

        @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
            CacheKey that = (CacheKey) o;
            if (hashCode != that.hashCode) return false;
            if (!clazz.equals(that.clazz)) return false;
            return Arrays.equals(paramTypes, that.paramTypes);
        }

        @Override
        public int hashCode() {
            return hashCode;
        }
    }

    private static final Map<CacheKey, CacheEntry> CACHE = new ConcurrentHashMap<>(256);

    // 公共API：获取public构造方法
    public static <T> Constructor<T> getConstructorIfAvailable(Class<T> clazz, Class<?>... paramTypes) {
        return getCachedConstructor(clazz, true, paramTypes);
    }

    // 公共API：获取任何访问级别的构造方法
    public static <T> Constructor<T> getConstructor(Class<T> clazz, Class<?>... paramTypes) {
        return getCachedConstructor(clazz, false, paramTypes);
    }

    // 核心缓存逻辑
    private static <T> Constructor<T> getCachedConstructor(Class<T> clazz, boolean onlyPublic, Class<?>... paramTypes) {
        AssertUtils.notNull(clazz, "Class must not be null");
        CacheKey key = new CacheKey(clazz, paramTypes);
        // 尝试从缓存获取
        CacheEntry entry = CACHE.get(key);
        if (entry != null) {
            // 检查访问级别是否满足要求
            if (!onlyPublic || entry.isPublic) {
                @SuppressWarnings("unchecked")
                Constructor<T> result = (Constructor<T>) entry.constructor;
                return result;
            }
            return null;
        }
        // 缓存未命中，执行查找
        Constructor<T> result = findConstructor(clazz, !onlyPublic, paramTypes);
        // 缓存找到的构造方法
        if (result != null) {
            CacheEntry newEntry = new CacheEntry(result);
            CACHE.put(key, newEntry);
            // 再次检查访问级别要求
            if (onlyPublic && !newEntry.isPublic) {
                return null;
            }
        }
        return result;
    }

    // 优化的查找逻辑
    private static <T> Constructor<T> findConstructor(Class<T> clazz, boolean includeNonPublic, Class<?>... paramTypes) {
        try {
            // 首先尝试获取public构造方法（更快）
            return clazz.getConstructor(paramTypes);
        } catch (NoSuchMethodException ex) {
            if (includeNonPublic) {
                try {
                    // 尝试获取非public构造方法
                    return clazz.getDeclaredConstructor(paramTypes);
                } catch (NoSuchMethodException e) {
                    return null;
                }
            }
            return null;
        }
    }

    // 清空缓存
    public static void clearCache() {
        CACHE.clear();
    }

    // 获取当前缓存大小
    public static int getCacheSize() {
        return CACHE.size();
    }
}